Skip to content

D2 + D3: measured autotune loop + arbiter fallback log (sm_120) - #294

Merged
gstoner merged 1 commit into
mainfrom
nvidia/d2-autotune
Jul 7, 2026
Merged

gstoner merged 1 commit into
mainfrom
nvidia/d2-autotune

Conversation

@gstoner

@gstoner gstoner commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Section B, items 2 & 3 — the measured autotune loop (D2) and arbiter fallback logging (D3), building on the matmul op-kind from #293. Verified on the live sm_120 box.

D2 — measured autotune loop (emit/autotune.py)

Layers on the D1 arbiter's existing measure seam. measured_arbitrate():

  1. F4-gates the candidates (only in-budget, correct kernels survive),
  2. times each survivor on-device (measure_latency, median-of-N after warmup),
  3. caches the fastest in a MeasureCache keyed by (device, target, op, shape-bucket, dtype)measure-at-first-miss (a re-query hits the cache, no re-timing).

Lead-safety holds end-to-end: only F4-passing, in-accuracy-budget candidates are ever timed, so a faster-but-wrong kernel can't win. runtime._nvidia_device_name() supplies the sm_<cc> device tag so a config measured on one device isn't reused on another.

Live on sm_120: times the shipped vs emitted GEMM lanes and caches the winner per bucket (shipped 0.476ms vs emitted 0.484ms on 64³ → picks the faster by latency, not tier).

D3 — arbiter fallback log (candidate.py)

Every arbitrated dispatch records (target, op, selected, tag) (_note_arbiter_dispatch, wired into run_arbitrated + run_measured_arbitrated). arbiter_dispatch_histogram() answers "did the compiled path win, silently degrade, or was there no candidate?" per (target, op):

  • won: a selected candidate ran a real kernel,
  • degraded: a candidate was selected but declined to the numpy reference at run time (the silent degrade),
  • no_candidate: nothing applied/verified.

The arbiter-layer analog of runtime.dispatch_fallback_log.

Verified

  • host-free: test_arbiter_autotune.py (5 — measured pick+cache, shape bucketing, won/degraded/no_candidate, histogram filter);
  • live sm_120: measured autotune caches the GEMM winner; the emitted lane forced on a ragged shape it can't run logs a degraded.

30 passed / 1 skipped; ruff + mypy clean; drift green.

Still open (this section)

  • Persist the cache as the committed fleet-shared autotune corpus (Theory §7.5 — hangs off MeasureCache.to_dict).
  • [AMD] gfx1151 wiring of the same loop.

Section C (flash-attn sm_120; generic CUDA lane past f32) is next.

🤖 Generated with Claude Code

D2 (measured autotune) — emit/autotune.py layers on the D1 arbiter's `measure`
seam: measured_arbitrate() F4-gates the candidates, times each survivor on-device
(measure_latency, median-of-N after warmup), and caches the fastest in a
MeasureCache keyed by (device, target, op, shape-bucket, dtype) — measure-at-
first-miss (a re-query hits the cache, no re-timing). Lead-safety holds: only
in-budget F4-passing candidates are timed, so a faster-but-wrong kernel can't win.
runtime._nvidia_device_name() supplies the sm_<cc> device tag. Live on sm_120:
times the shipped vs emitted GEMM lanes and caches the winner per bucket.

D3 (fallback log) — the arbiter records every dispatch as (target, op, selected,
tag) (candidate._note_arbiter_dispatch, wired into run_arbitrated +
run_measured_arbitrated); arbiter_dispatch_histogram() answers "did the compiled
path win, silently degrade, or was there no candidate?" per (target, op) — a
selection that ran but returned a reference tag is the silent degrade (the
arbiter-layer analog of runtime.dispatch_fallback_log). Proven host-free and live
(the emitted lane forced on a ragged shape it can't run logs a `degraded`).

Tests: test_arbiter_autotune.py (5 host-free — measured pick+cache, bucketing,
won/degraded/no_candidate, histogram filter) + 2 nvidia sm_120 live gates.
Still open: persist the cache as the committed fleet-shared corpus (Theory §7.5,
hangs off MeasureCache.to_dict); [AMD] gfx1151 wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gstoner
gstoner enabled auto-merge (squash) July 7, 2026 19:47

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 628bc922b8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +136 to +137
if c.name == rec.winner and c.applies_to(region) and c.available():
return c

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject cached winners that can't run the actual shape

When a cached autotune winner is reused, this only checks region-level applicability and availability, not whether the candidate can execute the current input shape. For example, NvidiaMmaGemmEmittedCandidate.applies_to() accepts all bf16/f16 matmuls, but its run() declines to the NumPy reference when M%16, N%8, or K%16 fail; after tuning an aligned shape in a power-of-two bucket such as 32x16x32, a ragged shape like 24x16x32 hits the same bucket and returns the emitted candidate without reconsidering the shipped GEMM, causing run_measured_arbitrated() to silently degrade to the reference. The cache hit needs an input-shape capability check, an exact/alignment-aware key, or a revalidation that excludes reference declines.

Useful? React with 👍 / 👎.

@gstoner
gstoner merged commit 979e11b into main Jul 7, 2026
14 checks passed
gstoner added a commit that referenced this pull request Jul 7, 2026
The NVIDIA 2D GEMM helpers took M,K from A and N from B but discarded B's K, so
a mismatched contraction (A is MxK, B is K2xN, K != K2) passed A's K to the C ABI
— which then copies K*N elements from a B buffer holding only K2*N, overreading
host memory or computing against the wrong slice instead of raising like
MatmulRegion.reference / the JIT path.

Both _nvidia_mma_gemm_2d and _nvidia_ptx_gemm_2d now validate rank-2 + matching K
BEFORE any side effect (so a malformed matmul fails fast, host-free, ahead of the
lib load). The shipped candidate previously had no such check (the emitted lane's
_aligned_2d already rejected it). Host-free regression test added.

Co-authored-by: angst <angstroms01@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@gstoner
gstoner deleted the nvidia/d2-autotune branch July 7, 2026 22:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant